﻿namespace Jsl.FxCop
{
    using System;
    using Microsoft.FxCop.Sdk;

    /// <summary>
    /// A utility class for working with methods.
    /// </summary>
    public static class MethodHelper
    {
        #region Public Methods
        /// <summary>
        /// Does the action if the member is the public dispose method.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <param name="action">The action.</param>
        public static void DoIfPublicDisposeMethod(this Member member, Action<Method> action)
        {
            if (member.IsPublicDisposeMethod())
            {
                action((Method)member);
            }
        }

        /// <summary>
        /// Does the action if the member is the virtual dispose method.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <param name="action">The action.</param>
        public static void DoIfVirtualDisposeMethod(this Member member, Action<Method> action)
        {
            if (member.IsVirtualDisposeMethod())
            {
                action((Method)member);
            }
        }

        /// <summary>
        /// Does the action if the member is the InitializeComponent method.
        /// </summary>
        /// <param name="member">The member to check.</param>
        /// <param name="action">The action to do.</param>
        public static void DoIfInitializeComponent(this Member member, Action<Method> action)
        {
            member.DoIfInitializeComponent(null, action);
        }

        /// <summary>
        /// Does the action if the member is the InitializeComponent method.
        /// </summary>
        /// <param name="member">The member to check.</param>
        /// <param name="derivesFrom">The <see cref="Type"/> the class containing the member must derive from.</param>
        /// <param name="action">The action to do.</param>
        public static void DoIfInitializeComponent(this Member member, Type derivesFrom, Action<Method> action)
        {
            var method = member as Method;
            if (method.IsInitializeComponentMethod())
            {
                action(method);
            }
        }

        /// <summary>
        /// Does the action if the type has an InitializeComponent method in it.
        /// </summary>
        /// <param name="type">The type to check.</param>
        /// <param name="action">The action to do.</param>
        public static void DoIfInitializeComponent(this TypeNode type, Action<Method> action)
        {
            var method = type.GetInitializeComponentMethod();
            if (method != null)
            {
                action(method);
            }
        }

        /// <summary>
        /// Gets the InitializeComponent method, if any.
        /// </summary>
        /// <param name="type">The type to check for the InitializeComponent method.</param>
        /// <returns>The InitializeComponent method, if any.</returns>
        public static Method GetInitializeComponentMethod(this TypeNode type)
        {
            var method = type.GetMethod(Identifier.For(WellKnownMethodNames.InitializeComponent));
            if (method.IsInitializeComponentMethod())
            {
                return method;
            }

            return null;
        }

        /// <summary>
        /// Determines whether the member is the public dispose method.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns><c>true</c> if the member is the public dispose method.</returns>
        public static bool IsPublicDisposeMethod(this Member member)
        {
            var method = member as Method;
            return (method != null)
                && (method.Name.Name == WellKnownMethodNames.Dispose)
                && method.IsPublic
                && !method.IsAbstract
                && !method.IsVirtual
                && (method.Parameters.Count == 0);
        }

        /// <summary>
        /// Determines whether the member is the virtual dispose method.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns><c>true</c> if the member is the virtual dispose method.</returns>
        public static bool IsVirtualDisposeMethod(this Member member)
        {
            var method = member as Method;
            return (method != null)
                && (method.Name.Name == WellKnownMethodNames.Dispose)
                && method.IsVirtual
                && (method.Parameters.Count == 1)
                && (method.Parameters[0].Type.FullName == WellKnownTypeNames.Boolean);
        }

        /// <summary>
        /// Tries to get InitializeComponent method from the member.
        /// </summary>
        /// <param name="member">The member to check.</param>
        /// <param name="derivesFrom">The <see cref="Type"/> the class containing the member must derive from.</param>
        /// <param name="method">The method or <c>null</c>.</param>
        /// <returns><c>true</c> if the member is the InitializeComponent method.</returns>
        [Obsolete("Use DoIfInitializeComponent instead.")]
        public static bool TryGetInitializeComponent(Member member, Type derivesFrom, out Method method)
        {
            // The member must be the InitializeComponent method.
            method = member as Method;
            return method.IsInitializeComponentMethod()
                && TypeNodeHelper.IsAssignableTo(method.DeclaringType, derivesFrom);
        }
        #endregion Public Methods

        #region Private Methods
        private static bool IsInitializeComponentMethod(this Method method)
        {
            return (method != null)
                && (method.Name.Name == WellKnownMethodNames.InitializeComponent)
                && (method.Parameters.Count == 0)
                && TypeNodeHelper.IsAssignableTo(method.DeclaringType, WellKnownTypeNames.Component);
        }
        #endregion Private Methods
    }
}